package com.example.elm_server_api.config;

import com.example.elm_server_api.filter.CustomAuthenticationFilter;
import com.example.elm_server_api.filter.CustomAuthorizationFilter;
import com.example.elm_server_api.handler.CustomAccessDeniedHandler;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.authentication.AuthenticationManager;
import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder;
import org.springframework.security.config.annotation.method.configuration.EnableGlobalMethodSecurity;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter;

/**
 * web安全配置
 * @author 张建平
 * @createtime 2022/7/26 下午5:14
 */
@Configuration
@EnableWebSecurity
//开启 Spring Security 方法级安全注解 @EnableGlobalMethodSecurity
@EnableGlobalMethodSecurity(prePostEnabled = true, securedEnabled = true, jsr250Enabled = true)
public class WebSecurityConfig extends WebSecurityConfigurerAdapter {

    @Autowired
    CustomAccessDeniedHandler customAccessDeniedHandler;

    @Autowired
    PasswordEncoder passwordEncoder;

    @Autowired
    UserDetailsService userDetailsService;

    @Value("${jwt.secret}") //application.yml  jwt:secret
    private String tokenSecret;


    /**
     * 声明认证管理器
     * @return
     * @throws Exception
     */
    @Bean
    @Override
    public AuthenticationManager authenticationManagerBean() throws Exception {
        return super.authenticationManagerBean();
    }

    @Override
    protected void configure(AuthenticationManagerBuilder auth) throws Exception {
        //当登录认证时系统会自动调用 userDetailsService.loadUserByUsername("xxxx")
        auth.userDetailsService(userDetailsService).passwordEncoder(passwordEncoder);
    }

    @Override
    protected void configure(HttpSecurity http) throws Exception {
        //禁止跨站请求攻击
        http.csrf().disable();
        //以下的请求可以任意访问
        http.authorizeRequests()
                .antMatchers("/meituan/login/**",
                    "/script/**",
                    "/js/**",
                    "/styles/**", // /**/*.css
                    "/css/**",
                    "/images/**",
                    "/webjars/**",
                    "/actuator/**").permitAll();

        //需要被授权访问的请求
        http.authorizeRequests()
                .antMatchers("/api/home/helloworld/**") //.antMatchers(HttpMethod.POST,"/api/users/**");
                .hasAnyAuthority("ROLE_USAER", "ROLE_ADMIN"); //只要满足任一角色权限即可访问

        //授权访问
        http.authorizeRequests().anyRequest().authenticated();

        //设置授权失败时的消息处理器
        http.exceptionHandling()
                .accessDeniedHandler(customAccessDeniedHandler);

        CustomAuthenticationFilter customAuthenticationFilter =
                new CustomAuthenticationFilter(authenticationManagerBean(), tokenSecret);

        //处理登录认证请求的API 入口, 默认的入口：/login
        customAuthenticationFilter.setFilterProcessesUrl("/meituan/logins");
        // 加入到安全框架中，拦截用户登录时的身份认证
        http.addFilter(customAuthenticationFilter);

        //添加访问授权过滤器，在UsernamePasswordAuthenticationFilter之前执行
        http.addFilterBefore(new CustomAuthorizationFilter(this.tokenSecret), UsernamePasswordAuthenticationFilter.class);
    }
}
